﻿using System;
using System.Linq;
using System.Windows.Forms;
using System.Xml.Linq;
using System.IO;
using System.Xml;

namespace ConexaoBD.CustomEDMX
{
    public partial class fmrMain : Form
    {

        private string fileName;
        private XDocument xml;

        public fmrMain()
        {
            InitializeComponent();
        }

        #region Eventos de GUI
        private void fmrMain_Load(object sender, EventArgs e)
        {

        }

        private void btnProcurarArquivo_Click(object sender, EventArgs e)
        {

            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                fileName = openFileDialog1.FileName;

                StreamReader sr = new StreamReader(fileName);

                txtArquivoSelecionado.Text = fileName;
                xml = XDocument.Load(sr);

                sr.Close();
            }
            openFileDialog1.Dispose();
        }

        private void btnAlteraEdmx_Click(object sender, EventArgs e)
        {

            if (ckbCriarBackup.Checked)
                GerarBackupArquivoOriginal();

            pgrProcessamento.Increment(20);
            AlteracaoRecursiva(
                     xml.Elements().
                         Elements().Where(el => el.Name.LocalName == "Runtime").
                             Elements().Where(el => el.Name.LocalName == "ConceptualModels").First()
                 );

            pgrProcessamento.Increment(20);
            AlteracaoRecursiva(
                xml.Elements().
                    Elements().Where(el => el.Name.LocalName == "Runtime").
                        Elements().Where(el => el.Name.LocalName == "Mappings").First()
            );
            pgrProcessamento.Increment(20);

            using (System.IO.StreamWriter arq = new System.IO.StreamWriter
                        (fileName, false))
            {
                arq.WriteLine(xml.ToString());
                arq.Close();
            }
            pgrProcessamento.Value = pgrProcessamento.Maximum; 
            
            MessageBox.Show("EDMX Alterado");
            pgrProcessamento.Value = 0;
        }

        private void ckbPrefixoClasse_CheckedChanged(object sender, EventArgs e)
        {
            txtPrefixoClasse.ReadOnly = !ckbPrefixoClasse.Checked;
        }

        private void ckbPrefixoAtributo_CheckedChanged(object sender, EventArgs e)
        {
            txtPrefixoAtributo.ReadOnly = !ckbPrefixoAtributo.Checked;
        }

        private void ckbSufixoClasse_CheckedChanged(object sender, EventArgs e)
        {
            txtSufixoClasse.ReadOnly = !ckbSufixoClasse.Checked;
        }

        private void ckbSufixoAtributo_CheckedChanged(object sender, EventArgs e)
        {
            txtSufixoAtributo.ReadOnly = !ckbSufixoAtributo.Checked;
        }
        #endregion

        #region Métodos Privados
        private void GerarBackupArquivoOriginal()
        {
            string extensao = ".backup_";

            extensao += DateTime.Today.Year.ToString();
            extensao += DateTime.Today.Month.ToString();
            extensao += DateTime.Today.Day.ToString();
            extensao += "_";
            extensao += DateTime.Now.Hour.ToString().PadLeft(2, '0');
            extensao += DateTime.Now.Minute.ToString().PadLeft(2, '0');


            Stream stream = new FileStream(fileName + extensao, FileMode.Create);

            XmlWriter xw = XmlWriter.Create(stream);

            xml.WriteTo(xw);

            xw.Close();
            stream.Close();
        }

        private void AlteracaoRecursiva(XElement e)
        {

            switch (e.Name.LocalName)
            {
                case "EntityContainer":
                    e.Attribute("Name").Value = FormataNome(e.Attribute("Name").Value);
                    break;

                case "EntitySet":
                    e.Attribute("Name").Value = FormataNome(e.Attribute("Name").Value);
                    string[] partes = e.Attribute("EntityType").Value.Split('.');
                    e.Attribute("EntityType").Value =
                        partes[0] + "." + FormataNome(partes[1]);
                    break;

                case "End":
                    e.Attribute("Role").Value = FormataNome(e.Attribute("Role").Value);

                    if (e.Attributes().Where(a => a.Name == "Type").Count() > 0)
                    {
                        string[] partes3 = e.Attribute("Type").Value.Split('.');
                        e.Attribute("Type").Value =
                            partes3[0] + "." + FormataNome(partes3[1]);
                    }

                    if (e.Attributes().Where(a => a.Name == "EntitySet").Count() > 0)
                        e.Attribute("EntitySet").Value = FormataNome(e.Attribute("EntitySet").Value);

                    break;

                case "EntityType":
                    e.Attribute("Name").Value = FormataNome(e.Attribute("Name").Value);
                    break;

                case "Property":
                    e.Attribute("Name").Value = FormataNome(e.Attribute("Name").Value);
                    break;

                case "NavigationProperty":
                    e.Attribute("Name").Value = FormataNome(e.Attribute("Name").Value);
                    e.Attribute("FromRole").Value = FormataNome(e.Attribute("FromRole").Value);
                    e.Attribute("ToRole").Value = FormataNome(e.Attribute("ToRole").Value);
                    break;

                case "Principal":
                    e.Attribute("Role").Value = FormataNome(e.Attribute("Role").Value);
                    break;

                case "PropertyRef":
                    e.Attribute("Name").Value = FormataNome(e.Attribute("Name").Value);
                    break;

                case "Dependent":
                    e.Attribute("Role").Value = FormataNome(e.Attribute("Role").Value);
                    break;

                case "EntityContainerMapping":
                    e.Attribute("CdmEntityContainer").Value = FormataNome(e.Attribute("CdmEntityContainer").Value);
                    break;

                case "EntitySetMapping":
                    e.Attribute("Name").Value = FormataNome(e.Attribute("Name").Value);
                    break;

                case "EntityTypeMapping":
                    string[] partes2 = e.Attribute("TypeName").Value.Split('.');
                    e.Attribute("TypeName").Value =
                        partes2[0] + "." + FormataNome(partes2[1]);
                    break;

                case "ScalarProperty":
                    e.Attribute("Name").Value = FormataNome(e.Attribute("Name").Value);
                    break;

                default:
                    break;
            }

            if (e.Elements().Count() > 0)
                foreach (var el in e.Elements())
                    AlteracaoRecursiva(el);
        }

        private string FormataNome(string nomeElemento)
        {

            if (ckbIniciaisMaiusculas.Checked) 
                nomeElemento = IniciaisMaiusculas(nomeElemento);

            if (ckbCammelCase.Checked) 
                nomeElemento = CammelCase(nomeElemento);

            if (ckbRemoverUnderlines.Checked)
                nomeElemento = RetiraUnderline(nomeElemento);

            return nomeElemento;
        }

        private string IniciaisMaiusculas(string nomeElemento)
        {
            if (Char.IsLetter(nomeElemento[0]))
                nomeElemento =
                    nomeElemento.Substring(0,1).ToString().ToUpper() +
                    nomeElemento.Substring(1);

            return nomeElemento;
        }

        private string CammelCase(string name)
        {
            //Caso nao exista nenhum underline, favor nao mexer nessa porra
            if (name.IndexOf("_") == -1)
            {
                //if (ckbIniciaisMaiusculas.Checked) name = name.Substring(0, 1).ToUpper() + name.Substring(1);
                return name;
            }

            string result = name;
            bool upperCase = false;

            result = string.Empty;
            for (int i = 0; i < name.Length; i++)
            {
                if (name[i] == ' ' || name[i] == '_')
                {
                    upperCase = true;
                }
                else
                {
                    //if (i == 0 || upperCase)
                    if (upperCase)
                    {
                        result += name[i].ToString().ToUpperInvariant();
                        upperCase = false;
                    }
                    else
                    {
                        result += name[i];
                    }
                }
            }

            return result;
        }

        private string RetiraUnderline(string nomeElemento)
        {
            return nomeElemento.Replace("_", "");
        }
        #endregion


    }
}
